﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;

namespace Universe.Cache.Tests
{
    class SampleThread
    {
        public readonly CancelToken Cancel;
        public readonly int Key;
        private Random rand = new Random();
        public Counter Counter = new Counter();
        public readonly WaitHandle Run;
        public ManualResetEvent Done = new ManualResetEvent(false);

        public SampleThread(CancelToken cancel, int key, WaitHandle run)
        {
            Cancel = cancel;
            Key = key;
            Run = run;
        }

        public void RunReader(int numFails, int numChanged, bool onlySingle)
        {
            Run.WaitOne();
            Stopwatch sw = Stopwatch.StartNew();
            int n = 0;
            while(!Cancel.IsCanceled)
            {
                TimeSpan elapsed = sw.Elapsed;

                if (++n % 50 == 0)
                {
                    Console.Write("\rReader: {0}", new DateTime(elapsed.Ticks).ToString("HH:mm:ss"));
                }

                string key;
                byte[] stamp;
                int index =
                    onlySingle
                        ? MyEnvironment.Instance.Snapshot.Count/2
                        : rand.Next(0, MyEnvironment.Instance.Snapshot.Count - 1);

                int next = rand.Next(100);
                if (next <= numFails)
                {
                    // fail to hit into cache
                    key = "no data";
                    stamp = new byte[30];
                }
                else if (next + numFails < numFails + numChanged)
                {
                    // changed
                    key = MyEnvironment.Instance.Snapshot[index].Key;
                    stamp = new byte[40];
                }
                else
                {
                    // hit!
                    key = MyEnvironment.Instance.Snapshot[index].Key;
                    stamp = MyEnvironment.Instance.Snapshot[index].Stamp;
                }

                byte[] value;
                var storage = MyEnvironment.Instance.Storage;
                storage.Get(key, stamp, out value);
                Counter.Inc();
            }

            TimeSpan d = sw.Elapsed;
            Console.WriteLine("\rReader: Done. Total requests/sec: {0}", (n / d.TotalSeconds).ToString("f1"));
            Done.Set();
        }

        public void RunWriter(bool onlySingle)
        {
            Run.WaitOne();
            Stopwatch sw = Stopwatch.StartNew();
            int n = 0;
            while (!Cancel.IsCanceled)
            {
                TimeSpan elapsed = sw.Elapsed;

                if (++n % 50 == 0)
                {
                    Console.Write("\rWriter: {0}", new DateTime(elapsed.Ticks).ToString("HH:mm:ss"));
                }

                string key;
                byte[] stamp;
                int index =
                    onlySingle
                        ? MyEnvironment.Instance.Snapshot.Count / 2
                        : rand.Next(0, MyEnvironment.Instance.Snapshot.Count - 1);

                byte[] value = new byte[1000];
                key = MyEnvironment.Instance.Snapshot[index].Key;
                stamp = new byte[40];

                var storage = MyEnvironment.Instance.Storage;
                storage.Put(key, stamp, DateTime.Now.AddDays(1), value);
                Counter.Inc();
            }

            TimeSpan d = sw.Elapsed;
            Console.WriteLine("\rWriter: Done. Total requests/sec: {0}", (n / d.TotalSeconds).ToString("f1"));
            Done.Set();
        }

        public class CancelToken
        {
            public volatile bool IsCanceled = false;

        }

    }
}
